use anyhow::Result;
use prost::Message;
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::net::{TcpListener, TcpStream, UdpSocket};
use tokio::sync::mpsc;
use tracing::{debug, error, info, trace, warn};

use crate::constants::WAR3_PORT;
use crate::network::ClientConnection;
use crate::{DataForward, MessageType, War3Message};
use crate::utils::{send_protobuf_message, transfer_data};

/// War3服务器代理，负责处理与远程客户端的连接
pub struct War3Server {
    /// 其他客户端的War3 IP地址
    pub other_war3_ip: String,
    /// 代理服务器地址
    pub proxy_server_addr: SocketAddr,
    /// 用于接收UDP数据的socket
    udp_socket: Arc<tokio::sync::Mutex<Option<Arc<UdpSocket>>>>,
    /// 本地War3游戏的IP地址，用于计算正确的广播地址
    local_war3_ip: String,
    /// 用于向本地网络发送UDP广播的socket发送器
    broadcast_socket_tx: Arc<tokio::sync::Mutex<Option<mpsc::UnboundedSender<Vec<u8>>>>>,
}

impl War3Server {
    /// 创建新的War3Server实例
    pub fn new(other_war3_ip: String, proxy_server_addr: SocketAddr, local_war3_ip: String) -> Self {
        Self {
            other_war3_ip,
            proxy_server_addr,
            udp_socket: Arc::new(tokio::sync::Mutex::new(None)),
            local_war3_ip,
            broadcast_socket_tx: Arc::new(tokio::sync::Mutex::new(None)),
        }
    }

    /// 启动TCP和UDP监听
    pub async fn start(
        self: Arc<Self>,
        connection: Arc<ClientConnection>,
        my_war3_ip: String,
    ) -> Result<()> {
        info!(
            "War3Server starting for remote client {}, local IP {}, game IP {}",
            self.other_war3_ip, my_war3_ip, self.local_war3_ip
        );

        // 初始化广播socket
        self.init_broadcast_socket().await?;

        let tcp_handle = {
            let this = Arc::clone(&self);
            tokio::spawn(async move {
                if let Err(e) = this.start_tcp_listener().await {
                    error!("TCP监听错误 {}: {}", this.other_war3_ip, e);
                }
            })
        };

        let udp_handle = {
            let this = Arc::clone(&self);
            let sender = connection.sender();
            tokio::spawn(async move {
                if let Err(e) = this.start_udp_listener(sender, my_war3_ip).await {
                    error!("UDP监听错误 {}: {}", this.other_war3_ip, e);
                }
            })
        };

        let _ = tokio::try_join!(tcp_handle, udp_handle);
        Ok(())
    }

    /// 启动TCP监听器
    async fn start_tcp_listener(&self) -> Result<()> {
        // 恢复原来的绑定地址，避免与本地War3游戏冲突
        let bind_addr = format!("{}:{}", self.other_war3_ip, WAR3_PORT);
        let listener = TcpListener::bind(&bind_addr).await?;
        info!(
            "War3Server TCP listener started on {}",
            bind_addr
        );

        loop {
            match listener.accept().await {
                Ok((local_stream, addr)) => {
                    info!(
                        "War3Server TCP accepted connection from {} on {}",
                        addr, bind_addr
                    );
                    let proxy_addr = self.proxy_server_addr;
                    let other_ip = self.other_war3_ip.clone();
                    tokio::spawn(async move {
                        if let Err(e) =
                            Self::handle_tcp_connection(local_stream, proxy_addr, other_ip).await
                        {
                            error!("处理TCP连接错误: {}", e);
                        }
                    });
                }
                Err(e) => {
                    error!("接受TCP连接失败: {}", e);
                }
            }
        }
    }

    /// 处理TCP连接
    async fn handle_tcp_connection(
        local_stream: TcpStream,
        proxy_addr: SocketAddr,
        other_war3_ip: String,
    ) -> Result<()> {
        // 连接到代理服务器，这里需要创建一个新的连接而不是复用现有连接
        let mut proxy_stream = TcpStream::connect(proxy_addr).await?;
        info!("War3Server connected to proxy server: {}", proxy_addr);

        // 发送WAR3_CONNECT消息
        let message = War3Message {
            r#type: MessageType::War3Connect as i32,
            source_ip: String::new(),
            target_ip: other_war3_ip.clone(),
            payload: Vec::new(),
        };

        send_protobuf_message(&mut proxy_stream, &message).await?;
        info!("War3Server sent WAR3_CONNECT message for {}", other_war3_ip);

        // 开始数据转发
        info!("War3Server starting TCP data transfer for {}", other_war3_ip);
        if let Err(e) = transfer_data(local_stream, proxy_stream).await {
            error!("War3Server TCP data transfer error: {}", e);
        }
        info!("War3Server TCP data transfer ended for {}", other_war3_ip);

        Ok(())
    }

    /// 启动UDP监听器
    async fn start_udp_listener(
        self: &Arc<Self>,
        sender: mpsc::UnboundedSender<War3Message>,
        _my_war3_ip: String, // 参数保留用于接口一致性，但当前实现中未使用
    ) -> Result<()> {
        // 绑定到other_war3_ip:6112，与Java版本保持一致
        // 这样可以避免与本地War3游戏的6112端口冲突
        let bind_addr = format!("{}:{}", self.other_war3_ip, WAR3_PORT);
        let socket = match UdpSocket::bind(&bind_addr).await {
            Ok(socket) => {
                info!("War3Server UDP listener bound to {}", bind_addr);
                socket
            }
            Err(_e) => {
                warn!("Failed to bind to {}, falling back to 0.0.0.0:{}", bind_addr, WAR3_PORT);
                let fallback_addr = format!("0.0.0.0:{}", WAR3_PORT);
                UdpSocket::bind(&fallback_addr).await?
            }
        };
        
        // 设置广播
        if let Err(e) = socket.set_broadcast(true) {
            warn!("设置UDP广播失败: {}, 继续运行", e);
        }
        
        // 保存socket用于发送数据
        let socket_arc = Arc::new(socket);
        {
            let mut udp_socket = self.udp_socket.lock().await;
            *udp_socket = Some(socket_arc.clone());
        }
        
        info!("War3Server UDP listener started on {}", bind_addr);
        let mut buf = vec![0u8; 8192];
        
        loop {
            match socket_arc.recv_from(&mut buf).await {
                Ok((len, addr)) => {
                    // 获取数据包来源IP
                    let source_ip = addr.ip().to_string();
                    
                    // 核心转发逻辑：只要数据包来源不是监听的虚拟IP本身，就转发给代理服务器
                    // 这与Java版本的逻辑完全一致：
                    // if (!packet.getAddress().getHostAddress().equals(otherWar3Ip)) {
                    //     connectionWar3ProxyServer.forwardUdpDataToServer(otherWar3Ip, packet.getData(), packet.getLength());
                    // }
                    if source_ip != self.other_war3_ip {
                        info!(
                            "War3Server received UDP data from {} (not {}), forwarding to proxy server",
                            source_ip, self.other_war3_ip
                        );
                        
                        info!(
                            "War3Server received UDP data: {} -> {}, {} bytes",
                            addr, bind_addr, len
                        );

                        // 转发到代理服务器
                        let data = buf[..len].to_vec();
                        let other_ip = self.other_war3_ip.clone();
                        let source_ip = source_ip.clone(); // 实际的数据来源IP
                        let sender_clone = sender.clone();

                        let other_ip_for_log = other_ip.clone();
                        let source_ip_for_log = source_ip.clone();
                        tokio::spawn(async move {
                            if let Err(e) = Self::forward_udp_to_server(
                                sender_clone,
                                source_ip, // 使用实际的数据来源IP
                                other_ip,  // target_ip是虚拟IP（other_war3_ip）
                                data,
                            )
                            .await
                            {
                                error!("转发UDP数据失败: {}", e);
                            } else {
                                info!("Successfully forwarded UDP data from {} to {} ({} bytes)", source_ip_for_log, other_ip_for_log, len);
                            }
                        });
                    } else {
                        // 忽略来自虚拟IP本身的数据（避免循环转发）
                        info!(
                            "War3Server ignored UDP data from {} (same as virtual IP {}): {} bytes",
                            source_ip, self.other_war3_ip, len
                        );
                    }
                }
                Err(e) => {
                    error!("接收UDP数据失败: {}", e);
                    break; // 出错时退出循环
                }
            }
        }

        Ok(())
    }

    /// 转发UDP数据到服务器
    /// 
    /// 参数说明：
    /// - from_ip: 数据包的实际来源IP（如192.168.23.2）
    /// - target_ip: 虚拟目标IP（如127.0.1.1），代理服务器会根据这个IP找到对应的真实客户端
    async fn forward_udp_to_server(
        sender: mpsc::UnboundedSender<War3Message>,
        from_ip: String,
        target_ip: String,
        data: Vec<u8>,
    ) -> Result<()> {
        let data_len = data.len();

        let data_forward = DataForward {
            from_ip: from_ip.clone(),
            data,
        };

        let message = War3Message {
            r#type: MessageType::DataForward as i32,
            source_ip: from_ip.clone(),  // source_ip是数据包的实际来源IP
            target_ip: target_ip.clone(), // target_ip是虚拟目标IP，代理服务器据此路由
            payload: data_forward.encode_to_vec(),
        };

        sender.send(message)?;
        info!(
            "War3Server forwarded UDP data: from={} to={} {} bytes",
            from_ip, target_ip, data_len
        );
        Ok(())
    }

    /// 初始化用于向本地网络广播的socket
    async fn init_broadcast_socket(&self) -> Result<()> {
        // 绑定到本地IP的随机端口，避免与War3游戏端口冲突
        // 使用本地IP而不是0.0.0.0，更精确地控制网络接口
        let bind_addr = format!("{}:0", self.local_war3_ip);
        let socket = match UdpSocket::bind(&bind_addr).await {
            Ok(socket) => {
                info!("Broadcast socket bound to {}", socket.local_addr()?);
                socket
            }
            Err(e) => {
                warn!("Failed to bind broadcast socket to {}, using 0.0.0.0:0: {}", bind_addr, e);
                UdpSocket::bind("0.0.0.0:0").await?
            }
        };
        socket.set_broadcast(true)?;
        
        // 创建一个通道用于发送数据
        let (tx, mut rx) = mpsc::unbounded_channel::<Vec<u8>>();
        {
            let mut broadcast_socket_tx = self.broadcast_socket_tx.lock().await;
            *broadcast_socket_tx = Some(tx);
        }
        
        // 启动广播任务
        let local_war3_ip = self.local_war3_ip.clone();
        
        tokio::spawn(async move {
            info!("War3Server broadcast task started");
            while let Some(data) = rx.recv().await {
                // 获取子网广播地址
                let broadcast_ip = Self::get_subnet_broadcast_address_static(&local_war3_ip)
                    .unwrap_or_else(|_| "255.255.255.255".to_string());
                let broadcast_addr: SocketAddr = format!("{}:{}", broadcast_ip, WAR3_PORT).parse().unwrap();
                
                info!(
                    "War3Server broadcasting UDP data: {} bytes to {}",
                    data.len(),
                    broadcast_addr
                );
                
                if let Err(e) = socket.send_to(&data, broadcast_addr).await {
                    error!("Failed to broadcast UDP data: {}", e);
                } else {
                    info!("War3Server successfully broadcasted {} bytes to {}", data.len(), broadcast_addr);
                }
            }
            debug!("War3Server broadcast task ended");
        });
        
        info!("War3Server broadcast socket initialized on 0.0.0.0:0");
        Ok(())
    }

    /// 获取子网广播地址 (静态方法)
    fn get_subnet_broadcast_address_static(ip_str: &str) -> Result<String> {
        // 对于远程代理场景，需要使用全局广播地址
        // 因为代理程序需要向本地网络广播UDP数据包，让本地War3游戏能够接收到
        info!("Using global broadcast address for remote proxy (IP: {})", ip_str);
        Ok("255.255.255.255".to_string())
    }

    /// 获取子网广播地址
    fn get_subnet_broadcast_address(&self, ip_str: &str) -> Result<String> {
        Self::get_subnet_broadcast_address_static(ip_str)
    }

    /// 发送UDP数据（用于接收服务器转发的数据）
    pub async fn send_udp_data(&self, data: &[u8]) -> Result<()> {
        info!(
            "War3Server sending UDP data: {} bytes to local War3 game at {}:{}",
            data.len(),
            self.local_war3_ip,
            WAR3_PORT
        );
        
        // 使用已初始化的广播通道发送数据
        let broadcast_socket_tx = self.broadcast_socket_tx.lock().await;
        if let Some(tx) = broadcast_socket_tx.as_ref() {
            // 克隆数据并通过通道发送
            if let Err(e) = tx.send(data.to_vec()) {
                warn!("Failed to send data through broadcast channel: {}", e);
                
                // 如果通过通道发送失败，创建临时socket发送（后备方案）
                drop(broadcast_socket_tx); // 释放锁
                self.send_udp_data_with_temp_socket(data).await?;
            } else {
                info!("War3Server successfully queued UDP data for broadcasting: {} bytes", data.len());
            }
        } else {
            // 如果广播通道不可用，创建临时socket发送（后备方案）
            drop(broadcast_socket_tx); // 释放锁
            self.send_udp_data_with_temp_socket(data).await?;
        }

        Ok(())
    }

    /// 使用临时socket发送UDP数据（后备方案）
    async fn send_udp_data_with_temp_socket(&self, data: &[u8]) -> Result<()> {
        info!("Broadcast socket not available, using temporary socket");
        
        // 绑定到0.0.0.0:0，让系统自动选择合适的本地地址和端口
        let socket = UdpSocket::bind("0.0.0.0:0").await?;
        socket.set_broadcast(true)?;
        
        // 直接使用广播地址发送数据，因为local_war3_ip是虚拟IP，不是真实的本地IP
        let broadcast_ip = self.get_subnet_broadcast_address(&self.local_war3_ip)?;
        let broadcast_addr: SocketAddr = format!("{}:{}", broadcast_ip, WAR3_PORT).parse()?;
        
        info!("Broadcasting UDP data to {} ({} bytes)", broadcast_addr, data.len());
        
        if let Err(e) = socket.send_to(data, broadcast_addr).await {
            error!("Failed to broadcast UDP data: {}", e);
            return Err(e.into());
        } else {
            info!(
                "War3Server successfully broadcasted UDP data: {} bytes to {}",
                data.len(),
                broadcast_addr
            );
        }
        
        Ok(())
    }
}